package imagem;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;


public class Img {
    
    private int[][] matrizAuxBi1;
    private int[][][] matrizAuxTri1;
    private int auxX, auxY, auxH,auxW;
    
    // Arquivo p/ Matriz *******************************************************
    public int[][][] arquivoToMatriz_RGB(String arquivo) {
        int[][][] matriz;
        try {
            BufferedImage imagem = ImageIO.read(new File(arquivo));
            int largura = imagem.getWidth();
            int altura = imagem.getHeight();
            matriz = new int[largura][altura][3];
            for (int linha = 0; linha < altura; linha++) {
                for (int coluna = 0; coluna < largura; coluna++) {
                    Color pixel = new Color(imagem.getRGB(coluna, linha));
                    matriz[coluna][linha][0] = pixel.getRed();
                    matriz[coluna][linha][1] = pixel.getGreen();
                    matriz[coluna][linha][2] = pixel.getBlue();
                }
            }
        } catch (IOException ex) {
            matriz = new int[0][0][0];
            Logger.getLogger(Img.class.getName()).log(Level.SEVERE, null, ex);
        }
        return matriz;
    }

    public int[][] arquivoToMatriz(String arquivo) {
        int[][] matriz;
        try {
            BufferedImage imagem = ImageIO.read(new File(arquivo));
            int largura = imagem.getWidth();
            int altura = imagem.getHeight();
            matriz = new int[largura][altura];
            for (int linha = 0; linha < altura; linha++) {
                for (int coluna = 0; coluna < largura; coluna++) {
                    Color pixel = new Color(imagem.getRGB(coluna, linha));
                    matriz[coluna][linha] = (pixel.getRed() + pixel.getGreen() + pixel.getBlue()) / 3;
                }
            }
        } catch (IOException ex) {
            matriz = new int[0][0];
            Logger.getLogger(Img.class.getName()).log(Level.SEVERE, null, ex);
        }
        return matriz;
    }

    // Matriz p/ Arquivo *******************************************************
    public void matrizToArquivo_RGB(int[][][] origem, String arquivo) {
        int largura = origem.length;
        int altura = origem[0].length;
        BufferedImage imagem = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_RGB);
        try {
            for (int linha = 0; linha < altura; linha++) {
                for (int coluna = 0; coluna < largura; coluna++) {
                    int r = origem[coluna][linha][0];
                    int g = origem[coluna][linha][1];
                    int b = origem[coluna][linha][2];
                    Color pixel = new Color(r, g, b);
                    imagem.setRGB(coluna, linha, pixel.getRGB());
                }
            }
            ImageIO.write(imagem, "JPEG", new File(arquivo));
        } catch (IOException ex) {
            Logger.getLogger(Img.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void matrizToArquivo(int[][] origem, String arquivo) {
        int largura = origem.length;
        int altura = origem[0].length;
        BufferedImage imagem = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_RGB);
        try {
            for (int linha = 0; linha < altura; linha++) {
                for (int coluna = 0; coluna < largura; coluna++) {
                    int valor = origem[coluna][linha];
                    Color pixel = new Color(valor, valor, valor);
                    imagem.setRGB(coluna, linha, pixel.getRGB());
                }
            }
            ImageIO.write(imagem, "JPEG", new File(arquivo));
        } catch (IOException ex) {
            Logger.getLogger(Img.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // Matriz p/ Imagem ********************************************************
    public BufferedImage matrizToImagem_RGB(int[][][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        BufferedImage imagem = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_RGB);
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = origem[coluna][linha][0];
                int g = origem[coluna][linha][1];
                int b = origem[coluna][linha][2];
                Color pixel = new Color(r, g, b);
                imagem.setRGB(coluna, linha, pixel.getRGB());
            }
        }
        return imagem;
    }

    public BufferedImage matrizToImagem(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        BufferedImage imagem = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_RGB);
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int valor = origem[coluna][linha];
                Color pixel = new Color(valor, valor, valor);
                imagem.setRGB(coluna, linha, pixel.getRGB());
            }
        }
        return imagem;
    }

    // Matriz p/ Matriz ********************************************************
    public int[][][] copiarMatriz_RGB(int[][][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][][] matriz = new int[largura][altura][3];
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                matriz[coluna][linha][0] = origem[coluna][linha][0];
                matriz[coluna][linha][1] = origem[coluna][linha][1];
                matriz[coluna][linha][2] = origem[coluna][linha][2];
            }
        }
        return matriz;
    }

    public int[][] copiarMatriz(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                matriz[coluna][linha] = origem[coluna][linha];
            }
        }
        return matriz;
    }

    public int[][] tonsCinza(int[][][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = origem[coluna][linha][0];
                int g = origem[coluna][linha][1];
                int b = origem[coluna][linha][2];
                int cinza = (int) (0.299 * r + 0.587 * g + 0.114 * b);
                matriz[coluna][linha] = cinza;
            }
        }
        return matriz;
    }

    // Auxiliar ****************************************************************
    public int limite_0_255(int valor) {
        if (valor < 0) {
            valor = 0;
        } else if (valor > 255) {
            valor = 255;
        }
        return valor;
    }

    // Brilho ******************************************************************
    public void brilho(int[][][] matriz, int brilho) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = matriz[coluna][linha][0] + brilho;
                int g = matriz[coluna][linha][1] + brilho;
                int b = matriz[coluna][linha][2] + brilho;
                matriz[coluna][linha][0] = limite_0_255(r);
                matriz[coluna][linha][1] = limite_0_255(g);
                matriz[coluna][linha][2] = limite_0_255(b);
            }
        }
    }

    public void brilho(int[][] matriz, int brilho) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int valor = matriz[coluna][linha] + brilho;
                matriz[coluna][linha] = limite_0_255(valor);
            }
        }
    }

    // Contraste ***************************************************************
    public void contraste(int[][][] matriz, double contraste) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = (int) (matriz[coluna][linha][0] * contraste);
                int g = (int) (matriz[coluna][linha][1] * contraste);
                int b = (int) (matriz[coluna][linha][2] * contraste);
                matriz[coluna][linha][0] = limite_0_255(r);
                matriz[coluna][linha][1] = limite_0_255(g);
                matriz[coluna][linha][2] = limite_0_255(b);
            }
        }
    }

    public void contraste(int[][] matriz, double contraste) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int valor = (int) (matriz[coluna][linha] * contraste);
                matriz[coluna][linha] = limite_0_255(valor);
            }
        }
    }

    // Binariza
    public void binariza(int[][] matriz, int limiar) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int valor = matriz[coluna][linha];
                if (valor >= limiar) {
                    valor = 255;
                } else {
                    valor = 0;
                }
                matriz[coluna][linha] = valor;
            }
        }
    }

    // Negativo
    public void negativo(int[][][] matriz) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = matriz[coluna][linha][0];
                int g = matriz[coluna][linha][1];
                int b = matriz[coluna][linha][2];
                matriz[coluna][linha][0] = 255 - r;
                matriz[coluna][linha][1] = 255 - g;
                matriz[coluna][linha][2] = 255 - b;
            }
        }
    }

    public void negativo(int[][] matriz) {
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int valor = matriz[coluna][linha];
                matriz[coluna][linha] = 255 - valor;
            }
        }
    }

    // Filtro Passa-Baixa
    public int[][] fpb_Media3x3(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int valor = (+1 * (origem[coluna - 1][linha - 1]) + 1 * (origem[coluna][linha - 1]) + 1 * (origem[coluna + 1][linha - 1])
                        + 1 * (origem[coluna - 1][linha]) + 1 * (origem[coluna][linha]) + 1 * (origem[coluna + 1][linha])
                        + 1 * (origem[coluna - 1][linha + 1]) + 1 * (origem[coluna][linha + 1]) + 1 * (origem[coluna + 1][linha + 1])) / 9;
                matriz[coluna][linha] = valor;
            }
        }
        return matriz;
    }

    public int[][] fpb_Mediana3x3(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int vetor[] = {
                    origem[coluna - 1][linha - 1],
                    origem[coluna][linha - 1],
                    origem[coluna + 1][linha - 1],
                    origem[coluna - 1][linha],
                    origem[coluna][linha],
                    origem[coluna + 1][linha],
                    origem[coluna - 1][linha + 1],
                    origem[coluna][linha + 1],
                    origem[coluna + 1][linha + 1]
                };
                //Ordena o vetor
                Arrays.sort(vetor);
                matriz[coluna][linha] = vetor[4];
            }
        }
        return matriz;
    }

    // Filtro Passa-Alta
    public int[][] fpa_Sobel(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int vh = (- 1 * (origem[coluna - 1][linha - 1]) - 2 * (origem[coluna][linha - 1]) - 1 * (origem[coluna + 1][linha - 1])
                        + 1 * (origem[coluna - 1][linha + 1]) + 2 * (origem[coluna][linha + 1]) + 1 * (origem[coluna + 1][linha + 1]));
                int vv = (- 1 * (origem[coluna - 1][linha - 1]) + 1 * (origem[coluna + 1][linha - 1])
                        - 2 * (origem[coluna - 1][linha]) + 2 * (origem[coluna + 1][linha])
                        - 1 * (origem[coluna - 1][linha + 1]) + 1 * (origem[coluna + 1][linha + 1]));
                int vs = (int) Math.sqrt(Math.pow(vh, 2) + Math.pow(vv, 2));
                vs = limite_0_255(vs);
                matriz[coluna][linha] = vs;
            }
        }
        return matriz;
    }

    public int[][] fpa_Gaussiana(int[][] origem) {
        int largura = origem.length;
        int altura = origem[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int valor = (-1 * (origem[coluna - 1][linha - 1]) - 1 * (origem[coluna][linha - 1]) - 1 * (origem[coluna + 1][linha - 1])
                        - 1 * (origem[coluna - 1][linha]) + 8 * (origem[coluna][linha]) - 1 * (origem[coluna + 1][linha])
                        - 1 * (origem[coluna - 1][linha + 1]) - 1 * (origem[coluna][linha + 1]) - 1 * (origem[coluna + 1][linha + 1]));
                matriz[coluna][linha] = limite_0_255(valor);
            }
        }
        return matriz;
    }
    
    public int[][][] pele1(int[][][] matriz){
        int largura = matriz.length;
        int altura = matriz[0].length;
        int[][][] matrizAux = new int[largura][altura][3];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int r = matriz[coluna][linha][0];
                int g = matriz[coluna][linha][1];
                int b = matriz[coluna][linha][2];
                if (r>95 && g>40 && b>20 && r-g>15 && r>b && Math.max(r,Math.max(g,b))-Math.min(r,Math.min(g,b))>15 ) {
                    matrizAux[coluna][linha][0]=r;
                    matrizAux[coluna][linha][1]=g;
                    matrizAux[coluna][linha][2]=b;
                }
                else {
                    matrizAux[coluna][linha][0]=0;
                    matrizAux[coluna][linha][1]=0;
                    matrizAux[coluna][linha][2]=0;
                }
            }
        }
        return matrizAux;
    }
    // *************************************************************************

    public int[][] diferenca(int limiar, int[][] matriz0, int[][] matriz1) {
        int largura = matriz0.length;
        int altura = matriz0[0].length;
        int[][] matriz = new int[largura][altura];
        for (int linha = 1; linha < altura - 1; linha++) {
            for (int coluna = 1; coluna < largura - 1; coluna++) {
                int valor = Math.abs(matriz1[coluna][linha] - matriz0[coluna][linha]);
                if (valor > limiar) {
                    matriz[coluna][linha] = 255;
                } else {
                    matriz[coluna][linha] = 0;
                }
            }
        }
        return matriz;
    }
    
    //Contagem de objetos
    public void objectCounter(int[][] matriz){
        int counter=1;
        //int largura = matriz.length;
        //int altura = matriz[0].length;
        matrizAuxBi1 = new int[matriz.length][matriz[0].length];
        matrizAuxBi1 = copiarMatriz(matriz);
        auxW = matrizAuxBi1.length;
        auxH = matrizAuxBi1[0].length;
        matrizAuxTri1 = new int[auxW][auxH][2];
        for (int linha = 1; linha < auxH; linha++) {
            for (int coluna = 1; coluna < auxW; coluna++) {
                if (objectScam(coluna, linha, counter)==true)
                    counter ++;
            }
        }
        System.out.print(counter-1);
    }
  
    private boolean objectScam(int coluna, int linha, int counter){
        if ((linha>0)&&(linha<auxH)&&(coluna>0)&&(coluna<auxW)) { //Se estiver no limite da imagem
            if (matrizAuxTri1[coluna][linha][1]==0) { //Se o pixel ainda n'ao foi verificado
                matrizAuxTri1[coluna][linha][1]=1; //marca verificado
                if (matrizAuxBi1[coluna][linha]==0){ //Se o ponto estiver preenchido
                    matrizAuxTri1[coluna][linha][0]=counter; //Marca o ponto
                    this.objectScam(coluna+1, linha, counter); //olha direita
                    this.objectScam(coluna, linha+1, counter); //olha baixo
                    this.objectScam(coluna-1, linha, counter); //olha esquerda
                    this.objectScam(coluna, linha-1, counter); //olha cima
                    /** Olha Diagonais
                    this.objectScam(coluna-1, linha-1, counter); //olha diagonal
                    this.objectScam(coluna+1, linha+1, counter); //olha diagonal
                    this.objectScam(coluna+1, linha-1, counter); //olha diagonal
                    this.objectScam(coluna-1, linha+1, counter); //olha diagonal
                    */
                    return true;
                }
                return false;
            }
            return false;
        }
        return false;
    }

    
    public void salvar(BufferedImage imagem) throws IOException{
        File imgSalva = new File("salvo.jpg");
        ImageIO.write(imagem, "jpg", imgSalva);
        System.out.println(imgSalva.getAbsolutePath());
        
        
    }
    
    public int retornaMediana(List<Integer> lista){
      //Ordena a lista
        Collections.sort(lista);
      //Pega o tamanho da lista soma 1 e divide por 2 para pegar o indice da mediana
      //Exemplo o tamanho da lista é 9 soma 1 da 10 e divide por 2 igual a 5 que é a mediana
        return lista.get((lista.size()+1)/2);
    }
    
    public int toRGB(double value){
        if(value > 255)
            return 255;
        else 
            if(value<0)
                return 0;
            else
                return (int)value;
    }
    
    public int toBinRGB(int value, int limiar, boolean reverse){
        if (reverse==false)
            if (value>=limiar)
                return 255;
            else
                return 0;
        else
            if (value>=limiar)
                return 0;
            else
                return 255;
    }
    
//***************<MÁSCARAS>***********************

    public void aplicarMascara(int[][] mascara, int coluna, int linha,int z){
        int mLargura=mascara.length;
        int mAltura=mascara[0].length;
        int x=0,y=0;
        List<Integer> lista = new ArrayList<Integer>();
        lista.clear();
        for (int l = linha-mAltura/2; l <= linha+mAltura/2; l++) {
            for (int c = coluna-mLargura/2; c <= coluna+mAltura/2; c++) {
                //int ponto = matriz[c][l][z];
                //lista.add(mascara[x][y]*ponto);
                y++;
            }
            y=0;
            x++;
        }
        //matriz[coluna][linha][z]=mediaMascara(lista);
    }
    
    public int mediaMascara(List<Integer> lista){
        int soma=0, total=0;
        for (int i=0; i<lista.size();i++){
            soma=soma+lista.get(i);
            total++;
        }
        return soma/total;
    }
    
    public int medianaMascara(List<Integer> lista){
        Collections.sort(lista);
        return lista.get((lista.size()+1)/2);
    }
    
    public int[][] mascaraDefault(){
        int[][] mascara = new int[3][3];
        mascara[0][0]=1;
        mascara[0][1]=1;
        mascara[0][2]=1;
        mascara[1][0]=1;
        mascara[1][1]=1;
        mascara[1][2]=1;
        mascara[2][0]=1;
        mascara[2][1]=1;
        mascara[2][2]=1;
        return mascara;
    }
    
    public int[][] mascaraSobelH(){
        int[][] mascara = new int[3][3];
        mascara[0][0]=-1;
        mascara[0][1]=-2;
        mascara[0][2]=-1;
        mascara[1][0]=0;
        mascara[1][1]=0;
        mascara[1][2]=0;
        mascara[2][0]=1;
        mascara[2][1]=2;
        mascara[2][2]=1;
        return mascara;
    }
    
    public int[][] mascaraSobelV(){
        int[][] mascara = new int[3][3];
        mascara[0][0]=-1;
        mascara[0][1]=0;
        mascara[0][2]=1;
        mascara[1][0]=-2;
        mascara[1][1]=0;
        mascara[1][2]=2;
        mascara[2][0]=-1;
        mascara[2][1]=0;
        mascara[2][2]=1;
        return mascara;
    }
    
//***************</MÁSCARAS>**********************



//***************<GRÁFICOS E HISTOGRAMAS>**********

    public double[][] histograma(int[][][] matriz){
        double hg[][] = new double[256][3];
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = matriz[coluna][linha][0];
                int g = matriz[coluna][linha][1];
                int b = matriz[coluna][linha][2];
                hg[r][0]++;
                hg[g][1]++;
                hg[b][2]++;
            }
        }
        return hg;
    }
    
    public double[] histograma(int[][] matriz){
        double hg[] = new double[256];
        int largura = matriz.length;
        int altura = matriz[0].length;
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int k = matriz[coluna][linha];
                hg[k]++;
            }
        }
        return hg;
    }
    
    public int[] histograma_equalizado(int[][] histograma) {
        int he[] = new int[256]; //Mapa da equalização.
        
        double cdf[] = new double[256]; //Cumulativo
        int i,j, k,n=0;
        
        for (i=0; i<256;i++){
            n = n + histograma[i][0];
        }
        
        cdf[0] = histograma[0][0]; 
        for (i=1;i<256;i++) {       // cdf of image
            cdf[i] = cdf[i-1] + histograma[i][0];
            he[i]=(int)Math.round(cdf[i]/n*255); //monta o mapa
        }
        return he;
    }
    
    public int[][] equalizar(int[][] imagem){ //recebe imagem original
        double hg[]; //histograma da imagem
        int he[] = new int[256]; //Mapa da equalização.
        int result[][] = new int[imagem.length][imagem[0].length]; //imagem equalizado
        
        double cdf[] = new double[256]; //Cumulativo
        int i,j, k,n;
        hg = histograma(imagem); //gera histograma da imagem original
        n = imagem.length * imagem[0].length; //pega qtd total de pixels da imagem
        
        cdf[0] = hg[0]; 
        for (i=1;i<256;i++) {       // cdf of image
            cdf[i] = cdf[i-1] + hg[i];
            he[i]=(int)Math.round(cdf[i]/n*255); //monta o mapa
        }
        
        for(i=0;i<imagem.length;i++) { //pega do mapa e transforma a imagem
            for(j=0;j<imagem[0].length;j++) {
                k = imagem[i][j];
                result[i][j] = (int)(he[k]); //atribui valor do mapa
            }
        }
        
        return result; //devolve imagem equalizado
    }

    public int[] projecaoHorizontal(int[][][] matriz){
        int largura = matriz.length;
        int altura = matriz[0].length;
        int projecao[] = new int[largura];
        for (int coluna = 0; coluna < largura; coluna++) {
            for (int linha = 0; linha < altura; linha++) {
                int r = matriz[coluna][linha][0];
                //int g = matriz[coluna][linha][1];
                //int b = matriz[coluna][linha][2];
                if (r==0) 
                    projecao[coluna]++; 
            }
        }
        return projecao;
    }
    
    public int[] projecaoVertical(int[][][] matriz){
        int largura = matriz.length;
        int altura = matriz[0].length;
        int projecao[] = new int[altura];
        for (int linha = 0; linha < altura; linha++) {
            for (int coluna = 0; coluna < largura; coluna++) {
                int r = matriz[coluna][linha][0];
                //int g = matriz[coluna][linha][1];
                //int b = matriz[coluna][linha][2];
                if (r==0) 
                    projecao[linha]++; 
            }
        }
        return projecao;
    }

//***************</GRÁFICOS E HISTOGRAMAS>**********
        
}


    /** Anotações
     * Filtro Passa Baixa (DiminuiÃ§Ã£o de ruido) usar com tons de cinza.
     * (L-1, C-1)   (L-1, C  )  (L-1, C+1)
     * (L  , C-1)   (L  , C  )  (L  , C+1)
     * (L+1, C-1)   (L+1, C  )  (L+1, C+1)

     * Filtro Passa Baixa (DiminuiÃ§Ã£o de ruido) usar com tons de cinza.
     * Mediana ordena e pega o do meio.
     * (L-1, C-1)   (L-1, C  )  (L-1, C+1)
     * (L  , C-1)   (L  , C  )  (L  , C+1)
     * (L+1, C-1)   (L+1, C  )  (L+1, C+1)

     * (x1(L-1, C-1) +  x2(L-1, C  ) + x3(L-1, C+1)
     * + x4(L  , C-1) +  x5(L  , C  ) + x6(L  , C+1)
     * + x7(L+1, C-1) +  x8(L+1, C  ) + x9(L+1, C+1))
     * /(x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9)
     * TODO Implementar usando mascara 3x3.
     * 
     * http://code.google.com/p/topicos-espciais/source/browse/trunk/Imagem/src/imagem/Img.java
     */